/******************************************************************************
* Copyright (C) 2018, Huada Semiconductor Co.,Ltd All rights reserved.
*
* This software is owned and published by:
* Huada Semiconductor Co.,Ltd ("HDSC").
*
* BY DOWNLOADING, INSTALLING OR USING THIS SOFTWARE, YOU AGREE TO BE BOUND
* BY ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT.
*
* This software contains source code for use with HDSC
* components. This software is licensed by HDSC to be adapted only
* for use in systems utilizing HDSC components. HDSC shall not be
* responsible for misuse or illegal use of this software for devices not
* supported herein. HDSC is providing this software "AS IS" and will
* not be responsible for issues arising from incorrect user implementation
* of the software.
*
* Disclaimer:
* HDSC MAKES NO WARRANTY, EXPRESS OR IMPLIED, ARISING BY LAW OR OTHERWISE,
* REGARDING THE SOFTWARE (INCLUDING ANY ACOOMPANYING WRITTEN MATERIALS),
* ITS PERFORMANCE OR SUITABILITY FOR YOUR INTENDED USE, INCLUDING,
* WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, THE IMPLIED
* WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE OR USE, AND THE IMPLIED
* WARRANTY OF NONINFRINGEMENT.
* HDSC SHALL HAVE NO LIABILITY (WHETHER IN CONTRACT, WARRANTY, TORT,
* NEGLIGENCE OR OTHERWISE) FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT
* LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION,
* LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING FROM USE OR
* INABILITY TO USE THE SOFTWARE, INCLUDING, WITHOUT LIMITATION, ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOSS OF DATA,
* SAVINGS OR PROFITS,
* EVEN IF Disclaimer HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
* YOU ASSUME ALL RESPONSIBILITIES FOR SELECTION OF THE SOFTWARE TO ACHIEVE YOUR
* INTENDED RESULTS, AND FOR THE INSTALLATION OF, USE OF, AND RESULTS OBTAINED
* FROM, THE SOFTWARE.
*
* This software may be replicated in part or whole for the licensed use,
* with the restriction that this Disclaimer and Copyright notice must be
* included with each copy of this software, whether used in part or whole,
* at all times.
*/
/******************************************************************************/
/** \file main.c
 **
 ** A detailed description is available at
 ** @link Sample Group Some description @endlink
 **
 **   - 2018-05-08  1.0  Lux First version for Device Driver Library of Module.
 **
 ******************************************************************************/

/******************************************************************************
 * Include files
 ******************************************************************************/ 
#include  <stdarg.h>
#include  <stdio.h>
#include  <stdlib.h>
#include  <math.h>
#include  <cpu.h>
#include  <lib_def.h>
#include  <lib_ascii.h>
#include  <lib_math.h>
#include  <lib_mem.h>
#include  <lib_str.h>
#include  <os.h>
#include  <app_cfg.h>
 
#include "gpio.h"

/******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/

/******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/

/******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/

/******************************************************************************
 * Local variable definitions ('static')                                      *
 ******************************************************************************/

/******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/

/*****************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/
static  OS_TCB          AppTaskStartTCB;
static  OS_TCB          AppTaskKeyTCB;
static  OS_TCB          AppTaskLedTCB;

static  CPU_STK         AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE];
static  CPU_STK         AppTaskKeyStk[APP_CFG_TASK_KEY_STK_SIZE];
static  CPU_STK         AppTaskLedStk[APP_CFG_TASK_LED_STK_SIZE];

OS_FLAG_GRP flag_grp;          /* 事件标志组对象 */
OS_TMR      my_tmr;            /* 声明软件定时器对象 */
		
static  void  AppTaskStart   (void *p_arg);
static  void  AppTaskKey     (void *p_arg);
static  void  AppTaskLed     (void *p_arg);
static  void  Gpio_Config    (void);

/**
 ******************************************************************************
 ** \brief  Main function of project
 **
 ** \return uint32_t return value, if needed
 **
 ** This sample
 **
 ******************************************************************************/
int32_t main(void)
{	
	OS_ERR      err;  

    OSInit(&err);   /* 初始化 uC/OS-III */
	
	/* 创建启动任务 */
	OSTaskCreate((OS_TCB      *)&AppTaskStartTCB,                           /* 任务控制块地址 */
                 (CPU_CHAR    *)"App Task Start",                           /* 任务名称 */
                 (OS_TASK_PTR  )AppTaskStart,                               /* 任务函数 */
                 (void        *)0,                                          /* 传递给任务函数（形参p_arg）的实参 */
                 (OS_PRIO      )APP_CFG_TASK_START_PRIO,                    /* 任务的优先级 */
                 (CPU_STK     *)&AppTaskStartStk[0],                        /* 任务堆栈的基地址 */
                 (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE_LIMIT,          /* 任务堆栈空间剩下1/10时限制其增长 */
                 (CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE,                /* 任务堆栈空间（单位：sizeof(CPU_STK)） */
                 (OS_MSG_QTY   )0,                                          /* 任务可接收的最大消息数 */
                 (OS_TICK      )0,                                          /* 任务的时间片节拍数（0表默认值OSCfg_TickRate_Hz/10） */
                 (void        *)0,                                          /* 任务扩展（0表不扩展） */
                 (OS_OPT       )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),/* 任务选项 */
                 (OS_ERR      *)&err);                                      /* 返回错误类型 */

	/* 启动多任务管理（交由uC/OS-III控制）*/			 
    OSStart(&err);                                                          
}

/* CPU IO口配置（包含LED灯和按键的配置）*/
static void Gpio_Config(void)
{
    stc_gpio_config_t stcGpioCfg;
	
    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);  /* 打开GPIO外设时钟门控 */
    
    stcGpioCfg.enDir = GpioDirIn;                            /* 端口方向配置->输入 */    
    stcGpioCfg.enDrv = GpioDrvL;                             /* 端口驱动能力配置->高驱动能力 */
    stcGpioCfg.enPuPd = GpioPu;                              /* 端口上下拉配置->上拉 */
    stcGpioCfg.enOD = GpioOdDisable;                         /* 端口开漏输出配置->开漏输出关闭 */
    stcGpioCfg.enCtrlMode = GpioAHB;                         /* 端口输入/输出值寄存器总线控制模式配置->AHB */
    
    Gpio_Init(GpioPortD, GpioPin4, &stcGpioCfg);             /* GPIO IO PD04初始化(PD04在STK上外接KEY(USER)) */
    
    stcGpioCfg.enDir = GpioDirOut;                           /* 端口方向配置->输出(其它参数与以上（输入）配置参数一致) */
    stcGpioCfg.enPuPd = GpioPd;                              /* 端口上下拉配置->下拉 */

    Gpio_Init(GpioPortD, GpioPin5, &stcGpioCfg);             /* GPIO IO PD05初始化(PD05在STK上外接LED(LED3)) */
	Gpio_ClrIO(GpioPortD, GpioPin5);                         /* LED熄灭 */
}

/* 软件定时器MyTmr的回调函数 */
void AppTmrCallback (OS_TMR *p_tmr, void *p_arg)
{
    OS_ERR      err;
	static  uint8_t  cnt = 0;
	
	cnt++;
	if (cnt%2 != 0)
    {
		OSFlagPost((OS_FLAG_GRP *)&flag_grp,
				   (OS_FLAGS     )0x02,
				   (OS_OPT       )OS_OPT_POST_FLAG_SET,
				   (OS_ERR      *)&err);
	}else
	{
		OSFlagPost((OS_FLAG_GRP *)&flag_grp,
				   (OS_FLAGS     )0x02,
				   (OS_OPT       )OS_OPT_POST_FLAG_CLR,
				   (OS_ERR      *)&err);
	
	}
}

/******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
static  void  AppTaskStart (void *p_arg)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;

    OS_ERR      err;

    (void)p_arg;                                          /* 消除警告 */

	Gpio_Config();                                        /* CPU端口配置 */
	
	/* 初始化CPU组件(时间戳、关中断时间测量和主机名) */
    CPU_Init();                                           /* CPU_Init()函数和OS_CPU_SysTickInit()函数要在OSStart()函数之后调用 */
	
	cpu_clk_freq = Sysctrl_GetHClkFreq();                 /* 获取系统参考时钟 */
    cnts         = cpu_clk_freq                           /* 计算时基(SysTick)计数器周期计数值 */
                 / (CPU_INT32U)OSCfg_TickRate_Hz;
    /* 初始化时基定时器(SysTick).   */
    OS_CPU_SysTickInit(cnts);                             /* CPU_Init()函数和OS_CPU_SysTickInit()函数要在OSStart()函数之后调用 */
	
	/* 创建事件标志组 */
	OSFlagCreate((OS_FLAG_GRP *)&flag_grp,                /* 指向信号量变量的指针 */
	             (CPU_CHAR    *)"flag for test",          /* 信号量的名字 */
				 (OS_FLAGS     )0,                        /* 信号量这里是指示事件发生，所以赋值为0，表示事件还没有发生 */
				 (OS_ERR      *)&err);                    /* 错误类型 */
				 
	/* 创建软件定时器 */
    OSTmrCreate((OS_TMR              *)&my_tmr,               /* 软件定时器对象 */
                (CPU_CHAR            *)"MySoftTimer",         /* 命名软件定时器 */
                (OS_TICK              )10,                    /* 定时器初始值，依10Hz时基计算，即为1s */
                (OS_TICK              )10,                    /* 定时器周期重载值，依10Hz时基计算，即为1s */
                (OS_OPT               )OS_OPT_TMR_PERIODIC,   /* 周期性定时 */
                (OS_TMR_CALLBACK_PTR  )AppTmrCallback,        /* 回调函数 */
                (void                *)"Timer Over!",         /* 传递实参给回调函数 */
                (OS_ERR              *)&err);                 /* 返回错误类型 */
							 
	/* 启动软件定时器 */						 
    OSTmrStart ((OS_TMR   *)&my_tmr, //软件定时器对象
                (OS_ERR   *)err);    //返回错误类型
	
	/* 创建 AppTaskKey 任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskKeyTCB,                              /*任务控制块地址 */
                 (CPU_CHAR   *)"App Task Key",                              /* 任务名称 */
                 (OS_TASK_PTR ) AppTaskKey,                                 /* 任务函数 */
                 (void       *) 0,                                          /* 传递给任务函数（形参p_arg）的实参 */
                 (OS_PRIO     ) APP_CFG_TASK_KEY_PRIO,                      /* 任务的优先级 */
                 (CPU_STK    *)&AppTaskKeyStk[0],                           /* 任务堆栈的基地址 */
                 (CPU_STK_SIZE) APP_CFG_TASK_KEY_STK_SIZE / 10,             /* 任务堆栈空间剩下1/10时限制其增长 */
                 (CPU_STK_SIZE) APP_CFG_TASK_KEY_STK_SIZE,                  /* 任务堆栈空间（单位：sizeof(CPU_STK)） */
                 (OS_MSG_QTY  ) 5u,                                         /* 任务可接收的最大消息数 */
                 (OS_TICK     ) 0u,                                         /* 任务的时间片节拍数（0表默认值OSCfg_TickRate_Hz/10） */
                 (void       *) 0,                                          /* 任务扩展（0表不扩展） */
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), /* 任务选项 */
                 (OS_ERR     *)&err);                                       /* 返回错误类型 */
    
	/* 创建 LED1 任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskLedTCB,                              /* 任务控制块地址 */
                 (CPU_CHAR   *)"App Task Led",                              /* 任务名称 */
                 (OS_TASK_PTR ) AppTaskLed,                                 /* 任务函数 */
                 (void       *) 0,                                          /* 传递给任务函数（形参p_arg）的实参 */
                 (OS_PRIO     ) APP_CFG_TASK_LED_PRIO,                      /* 任务的优先级 */
                 (CPU_STK    *)&AppTaskLedStk[0],                           /* 任务堆栈的基地址 */
                 (CPU_STK_SIZE) APP_CFG_TASK_LED_STK_SIZE / 10,             /* 任务堆栈空间剩下1/10时限制其增长 */
                 (CPU_STK_SIZE) APP_CFG_TASK_LED_STK_SIZE,                  /* 任务堆栈空间（单位：sizeof(CPU_STK)） */
                 (OS_MSG_QTY  ) 5u,                                         /* 任务可接收的最大消息数 */
                 (OS_TICK     ) 0u,                                         /* 任务的时间片节拍数（0表默认值OSCfg_TickRate_Hz/10） */
                 (void       *) 0,                                          /* 任务扩展（0表不扩展） */
                 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), /* 任务选项 */
                 (OS_ERR     *)&err);                                       /* 返回错误类型 */
		
	OSTaskDel ( & AppTaskStartTCB, & err );                                 /* 删除起始任务本身，该任务不再运行 */
}

/* 按键任务，每检测到一次按键按下，发布一次SemOfKey */
static void AppTaskKey (void *p_arg)
{
	OS_ERR      err;
	
	(void)p_arg;
					 							 
	while (DEF_TRUE) {                                               /* 任务体，通常写成一个死循环 */
		/* 检测PD04电平(USER按键是否按下(低电平)) */
		if (FALSE == Gpio_GetInputIO(GpioPortD, GpioPin4))
		{
			OSFlagPost((OS_FLAG_GRP *)&flag_grp,
			           (OS_FLAGS     )0x01,
			           (OS_OPT       )OS_OPT_POST_FLAG_SET,
			           (OS_ERR      *)&err);
        }else
        {
			OSFlagPost((OS_FLAG_GRP *)&flag_grp,
			           (OS_FLAGS     )0x01,
			           (OS_OPT       )OS_OPT_POST_FLAG_CLR,
			           (OS_ERR      *)&err);
        }		
        OSTimeDlyHMSM( 0, 0, 0, 500, OS_OPT_TIME_DLY, &err);          /* 延时50ms */
	}	
}

/* LED任务，等待SemOfKey信号量，收到一次信号量，闪烁一次 */
static void AppTaskLed (void *p_arg)
{
	OS_ERR       err;
	
	(void)p_arg;
	
	while (DEF_TRUE)
	{
		OSFlagPend((OS_FLAG_GRP *)&flag_grp,             /* 等待该信号量被发布 */
				   (OS_FLAGS     )(0x01 | 0x02),         /* 无期限等待 */
				   (OS_TICK      )0,                     /* 无期限等待 */
				   (OS_OPT       )OS_OPT_PEND_FLAG_SET_ALL |
		                          OS_OPT_PEND_BLOCKING,  /* 如果没有信号量可用就等待 */
				   (CPU_TS      *)0,                     /* 获取信号量最后一次被发布的时间戳 */
				   (OS_ERR      *)&err);                 /* 返回错误类型 */
		
		Gpio_SetIO(GpioPortD, GpioPin5);              /* LED点亮 */
		
		OSFlagPend((OS_FLAG_GRP *)&flag_grp,             /* 等待该信号量被发布 */
				   (OS_FLAGS     )(0x01 | 0x02),         /* 无期限等待 */
				   (OS_TICK      )0,                     /* 无期限等待 */
				   (OS_OPT       )OS_OPT_PEND_FLAG_CLR_ANY |
		                          OS_OPT_PEND_BLOCKING,  /* 如果没有信号量可用就等待 */
				   (CPU_TS      *)0,                     /* 获取信号量最后一次被发布的时间戳 */
				   (OS_ERR      *)&err);                 /* 返回错误类型 */
		
		Gpio_ClrIO(GpioPortD, GpioPin5);              /* LED熄灭 */
		
	}
}
